package com.gitee.wsl.unit.angle

import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size

/**
 * Represents an angular sector of the full circle as a section between a min and max angle. Provides
 * for testing if an angle falls within the sector.
 */
data class AngularSector(val minAngle: AngleUnit, val maxAngle: AngleUnit) {
    val normalizedMin = normalize(minAngle.toDegrees().value)
    val normalizedMax = normalize(maxAngle.toDegrees().value)

    /**
     * Tests whether the provided [angle] is within this sector.
     */
    fun contains(angle: AngleUnit): Boolean {
        @Suppress("MagicNumber")
        val normalizedAngle = (angle.toDegrees().value % 360.0 + 360.0) % 360.0

        return if (normalizedMin > normalizedMax) { // straddling the 0-degree line
            normalizedAngle > normalizedMin || normalizedAngle < normalizedMax
        } else {
            normalizedAngle in normalizedMin..normalizedMax
        }
    }

    private fun normalize(angle: Double): Double {
        @Suppress("MagicNumber")
        return (angle.toDegrees().value % 360.0 + 360.0) % 360.0
    }

    companion object{
        // These sectors define breakpoints where angular axis labels will be anchored to different points on the label
        val topSector = AngularSector(255.0.deg, 285.0.deg)
        val bottomSector = AngularSector(75.0.deg, 105.0.deg)
        val rightSector = AngularSector((-15.0).deg, 15.0.deg)
        val leftSector = AngularSector(165.0.deg, 195.0.deg)
        val topRightSector = AngularSector(285.0.deg, 345.0.deg)
        val bottomRightSector = AngularSector(15.0.deg, 75.0.deg)
        val bottomLeftSector = AngularSector(105.0.deg, 165.0.deg)
        val topLeftSector = AngularSector(195.0.deg, 255.0.deg)

    }
}

/**
 * Computes how much a label should be offset to place it's anchor
 * point at the target position given an angle for its placement and its size.
 *
 * @param angle Angle in radians
 * @param label Size of the label to have its offset computed
 */
fun AngleUnit.computeLabelPositionOffset(label: Size): Offset {
    return when {
        AngularSector.topSector.contains(this) -> Offset(-label.width / 2f, -label.height)
        AngularSector.bottomSector.contains(this) -> Offset(-label.width / 2.0f, 0f)
        AngularSector.rightSector.contains(this) -> Offset(0f, -label.height / 2.0f)
        AngularSector.leftSector.contains(this) -> Offset(-label.width, -label.height / 2.0f)
        AngularSector.topRightSector.contains(this) -> Offset(0f, -label.height)
        AngularSector.bottomRightSector.contains(this) -> Offset(0f, 0f)
        AngularSector.bottomLeftSector.contains(this) -> Offset(-label.width, 0f)
        AngularSector.topLeftSector.contains(this) -> Offset(-label.width, -label.height)
        else -> Offset(0f, 0f) // shouldn't happen
    }
}